

module ep4c_usb (
                clk,
					 reset_n,
					 U_FLAGA,
					 U_FLAGB,
					 U_FLAGC,
                U_SLOE,
                U_FLAGD_SLCS,
					 U_SLWR,
					 U_SLRD,
                U_FIFOADR,
					 U_PKEND,
                U_DB,
					 U_IFCLK,
					 U_CLKOUT,
					 CLKOUT,
					 U_XTALIN,
					 U_IFCLK_90,
					 U_IFCLKOUT,
					 led,
					 led2,
					 stateChange,
					 clk24M,
					 U_FLAGAOUT,
					 U_FLAGBOUT,
					 U_FLAGCOUT,
					 fastClk
             )
;

  input    	   		clk,reset_n;//48 mhz
  input	   			U_FLAGA,U_FLAGB,U_FLAGC,U_CLKOUT;
  
  output  CLKOUT, stateChange;

  
  output  				U_SLOE,U_FLAGD_SLCS,U_SLWR,U_SLRD , U_PKEND ,led ,fastClk,led2;
  output					U_IFCLK, U_XTALIN , U_IFCLK_90,U_IFCLKOUT, clk24M,U_FLAGAOUT,U_FLAGBOUT,U_FLAGCOUT; //U_XTALIN 24Mhz
  output   [  1: 0] 	U_FIFOADR;
  reg 		[1:0] 	U_FIFOADR;
  
  reg U_SLOE,U_FLAGD_SLCS,U_PKEND;
  reg  led , stateChange,led2;
  
  inout  [ 15: 0] 	U_DB;
  
  reg 	[ 15: 0]		usb_reply;

  
  assign U_DB= (STATE_NUM == USB_WDATA)?usb_reply:16'hzzzz;
  
  altpll0 pll0( clk, U_IFCLK,	U_XTALIN , U_IFCLK_90, fastClk);
  assign clk24M = U_XTALIN;
  assign CLKOUT = U_CLKOUT;
  assign U_IFCLKOUT = U_IFCLK;  //180 degree with U_IFCLK_180
	 
  assign U_FLAGAOUT = U_FLAGA;
  assign U_FLAGBOUT = U_FLAGB;
  assign U_FLAGCOUT = U_FLAGC;
  
//----------------------------------------------------------------
//reg [15:0]pkendcount;
//----------------------------------------------------------------
parameter USB_IDLE    = 2'd0; 
parameter USB_RDATA   = 2'd1; 
parameter USB_WDATA   = 2'd2; 

//----------------------------------------------------------------
reg [1:0] STATE_NUM;

reg [7:0] errorNum;
reg [7:0]num;
reg [8:0]writeNum;
reg [7:0] usbReadDataCheck;

  assign U_SLRD = ( ( STATE_NUM == USB_RDATA) ? U_IFCLK_90 :1'd1);
  assign U_SLWR = ( ( STATE_NUM == USB_WDATA) ? U_IFCLK_90  :1'd1);
  
 reg 	[ 10: 0]		usb_idleTime;
 parameter IDLETIME  = 11'h0f;
 
always@(posedge U_IFCLK or negedge reset_n)
begin
   if (!reset_n) begin	
							STATE_NUM <= USB_IDLE;
							U_SLOE<=1'd1;
							num<=8'h0;
							U_FLAGD_SLCS <= 1'd0;
							writeNum <= 9'd0;
							U_PKEND <= 1'd1;
							usb_idleTime <= IDLETIME;
							stateChange <= 0;
							usbReadDataCheck <= 8'hff;
							usbDataRead <= 16'd0;
							end
   else	begin
			case(STATE_NUM)
			USB_IDLE:	begin
								num<=8'hff;
								U_PKEND <= 1'd1;
								if( usb_idleTime > 0)
									usb_idleTime <= usb_idleTime - 1'd1;
								if( usb_idleTime == 1'd0)
								begin
									if( U_FLAGB )//ep2 not empty
									begin
										STATE_NUM <=USB_RDATA;
										U_FIFOADR <=2'b00;
										U_SLOE<=1'd0;
										usbReadDataCheck <= 8'hff;
									end
									else
									begin
										STATE_NUM<=USB_WDATA;
										U_FIFOADR <=2'b10;
										writeNum <= 9'd0;
										U_SLOE<=1'd1;
									end
								end
							end								
			USB_RDATA:	begin
							usbReadDataCheck <= usbReadDataCheck + 1'd1;
							usbDataRead <= U_DB;
							if( !U_FLAGB)	//ep2 empty
								begin
									STATE_NUM<=USB_IDLE;
									usb_idleTime <= IDLETIME;
									U_SLOE<=1'd1;
									stateChange <= !stateChange;
								end
							else	num<=num-8'h1;
							end
			USB_WDATA: begin
								writeNum <= writeNum + 1'd1;
								if ( writeNum == 9'd511) begin
									STATE_NUM <= USB_IDLE;
									stateChange <= !stateChange;
									usb_idleTime <= IDLETIME;
									U_PKEND <= 1'd0;
								end
						  end
			default:;
			endcase
			end
end

reg [15:0] usbDataRead;
always@(posedge U_IFCLK_90 or negedge reset_n)
begin
   if (!reset_n) begin	
							usb_reply <= 15'd0;
							led <= 1'd0;
							errorNum <= 8'd0;
					end
   else	
	begin
		case(STATE_NUM)
				USB_RDATA:	begin
								if( ( usbDataRead[15:8] != (usbDataRead[7:0] ) ) || (usbReadDataCheck[7:0] != usbDataRead[7:0]) )
								begin
									led <= !led;
									errorNum <= errorNum + 1'd1;
									if( errorNum > 8'd10)
										led <= !led;
								end
								else
									led <= 1'd0;	
								end
				USB_WDATA: begin
								usb_reply[7:0] <= writeNum[7:0] + 8'd2;
								usb_reply[15:8] <= writeNum[7:0]+ 8'd1;
							  end
				default:;
		endcase
	end
end

always@(posedge fastClk or negedge reset_n)
begin
   if (!reset_n) begin	
							led2 <= 1'd0;
							end
   else	
	begin
		case(STATE_NUM)
				USB_RDATA:	begin
								if( ( usbDataRead[15:8] > 8'hfd) )
									led2 <= 1'd1;
								else
									led2 <= 1'd0;	
								end
				default:;
		endcase
	end
end


  endmodule
  